//pending fulfilled rejected
class Promise {
    constructor(fn) {
        // 成功
        this.state = 'pending'
        this.value = undefined // 初始值
        this.reason = undefined // 失败原因
        this.onFulfilledfn = [] // 存放成功的数组
        this.onRejectedfn = [] // 存放失败的数组
        let resolve = (value) => {
            if (this.state === 'pending') {
                this.state = 'fulfilled'
                this.value = value
                this.onFulfilledfn.forEach((fn) => {
                    fn()
                })
            }
        }
        // 失败
        let reject = (reason) => {
            if (this.state === 'pending') {
                this.state === 'reject'
                this.reason = reason
                this.onRejectedfn.forEach((fn) => {
                    fn()
                })
            }
        }
        // 立即执行
        try {
            fn(resolve, reject)
        } catch (error) {
            reject(error)
        }
    }
    /**
     * 
     * @param {*} onFulfilled 
     * @param {*} onRejected 
     * Promose A+ 规定 onFulfilled 和 onRejected必须都是可选参数，如果他们不是函数必须被忽略
     * onFulfilled返回一个普通的值，成功时直接等于 value => value
     * onRejected返回一个普通的值，失败时如果直接等于 value => value，则会跑到下一个then中的onFulfilled中，
     * 所以直接扔出一个错误reason => throw err 2、秘籍规定onFulfilled或onRejected不能同步被调用，必须异步调用。我们就用setTimeout解决异步问题
     * 如果onFulfilled或onRejected报错，则直接返回reject()
     */
    then(onFulfilled, onRejected) {
        // onFulfilled如果不是函数，就忽略onFulfilled，直接返回value
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        // onRejected如果不是函数，就忽略onRejected，直接扔出错误
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
        // 链式调用,new Promise() 返回一个promise对象
        let promise2 = new Promise((resolve, reject) => {
            if (this.state === 'fulfilled') {
                // 用setTimeOut 模拟异步函数.(值得注意的是setTimeOut是下一轮的宏任务，但是resolve()是添加到微任务的执行栈中)
                setTimeout(() => {
                    try {
                        let x = onFulfilled(this.value)
                        // resolvePromise, 处理自己return的promise和默认的promise2的关系
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            }
            if (this.state === 'rejected') {
                setTimeout(() => {
                    try {
                        let x = onRejected(this.value)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            }
            // 添加到执行数组里面
            if (this.state === 'pending') {
                this.onFulfilledfn.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value)
                            resolvePromise(promise2, x, resolve, reject)   
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
                this.onRejectedfn.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.value)
                            resolvePromise(promise2, x, resolve, reject) 
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
            }
        })
    }
}

function resolvePromise(promise2, x, resolve, reject) {
    // 循环引用报错
    if (x === promise2) {
        return reject(new TypeError('Chaining cycle detected for promise'))
    }
    // 防止多次调用
    let called
    if(x !== null && (typeof x === 'object' || typeof x === 'function')) {
        try {
            let then = x.then
            // 如果then是函数，就默认是promise了
            if (typeof then === 'function') {
                // 就让then执行 第一个参数是this   后面是成功的回调 和 失败的回调
                then.call((x, y) => {
                    // 成功和失败只能调用一个
                    if (called) return
                    called = true
                    // resolve的结果依旧是promise 那就继续解析
                    resolvePromise(promise2, y, resolve, reject)
                }, err => {
                    if (called) return
                    called = true
                    // 失败就直接返回失败的原因
                    reject(err)
                })
            } else {
                // 不是对象和函数，是value成功。
                resolve(x)
            }
        } catch (error) {
            if (called) return
            called = true
            // 取then出错了那就不要在继续执行了
            reject(error)
        }
    } else {
        // 成功
        resolve(x)
    }
}

let p = new Promise(function(resolve, reject) {
    console.log('执行');
    setTimeout(() => {
        resolve(3)
    }, 1000)
})

// p.then(function(res) {
//     console.log(res);
// }, function(err) {
//     console.log(err);
// })
p.then(function(res) {
    console.log(res);
}).then(function(res) {
    console.log('res--', res);
}).then(function(res) {
    console.log('res------', res);
})

// 目前是通过他测试 他会测试一个对象
// 语法糖
// Promise.defer = Promise.deferred = function () {
//     let dfd = {}
//     dfd.promise = new Promise((resolve,reject)=>{
//       dfd.resolve = resolve;
//       dfd.reject = reject;
//     });
//     return dfd;
//   }
//   module.exports = Promise;
  //npm install promises-aplus-tests 用来测试自己的promise 符不符合promisesA+规范